package nj.yb.server;

import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import nj.yb.entity.group.GroupChat;
import nj.yb.entity.message.ChatMessage;
import nj.yb.entity.request.*;
import nj.yb.entity.user.Friend;
import nj.yb.entity.user.User;
import nj.yb.mapper.ChatMessageMapper;
import nj.yb.mapper.FriendMapper;
import nj.yb.mapper.GroupChatMapper;
import nj.yb.mapper.UserMapper;
import nj.yb.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ChatServerHandler extends SimpleChannelInboundHandler {
    //用户id-channel映射
    private static final Map<Integer,Channel> USER_CHANNEL_MAP = new HashMap<>();
    //所有的在线通道
    private static final ChannelGroup ALL_CHANNELS = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    //当前用户信息
    private User currentUser;
    //时间格式化工具
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //mapper
    private final UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class);
    private final FriendMapper friendMapper = MyBatisUtils.getMapper(FriendMapper.class);
    private final ChatMessageMapper chatMessageMapper = MyBatisUtils.getMapper(ChatMessageMapper.class);
    private final GroupChatMapper groupChatMapper = MyBatisUtils.getMapper(GroupChatMapper.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object o) throws Exception {
        Channel channel = ctx.channel();
        String msg = o.toString();
        try{
            //解析JSON请求
            Map<String,Object> request = JSON.parseObject(msg,Map.class);
            String type = (String) request.get("type");
            switch (type){
                case RequestType.REGISTER:
                    handleRegister(request,channel);
                    break;
                case RequestType.LOGIN:
                    handleLogin(request,channel);
                    break;
                case RequestType.FRIEND_LIST:
                    handleFriendList(request,channel);
                    break;
                case RequestType.CHAT:
                    handleChat(request,channel);
                    break;
                case RequestType.HISTORY:
                    handleHistory(request,channel);
                    break;
                case RequestType.GetNotRead:
                    handleNotRead(request,channel);
                    break;
                case RequestType.ADD_FRIEND:
                    handleAddFriend(request,channel);
                    break;
                case RequestType.GetGroupList:
                    handleGetGroupList(request,channel);
                    break;
                case RequestType.JOIN_GROUP:
                    handlerAdded();
                    break;
                default:
                    channel.writeAndFlush("不能识别的请求！！！");
            }
        }catch (Exception e){
            e.printStackTrace();
            channel.writeAndFlush("请求格式错误！！！\n");

        }
    }


    private void handleGetGroupList(Map<String,Object> request,Channel channel){
        if(currentUser == null){
            channel.writeAndFlush("请先登录\n");
            return;
        }
        GetGroupListRequest getGroupListRequest = JSON.parseObject(JSON.toJSONString(request), GetGroupListRequest.class);
        String username = getGroupListRequest.getUsername();
        List<GroupChat> groups = groupChatMapper.getGroupsByMember(username);

        //构建响应
        Map<String,Object> respones = new HashMap<>();
        respones.put("type","grouplist");
        respones.put("groups",groups);
        respones.put("count",groups.size());

        channel.writeAndFlush(JSON.toJSONString(respones)+"\n");
    }

    /**
     * 处理查询未读消息的请求
     * @param request
     * @param channel
     */
    private void handleNotRead(Map<String, Object> request, Channel channel) {
        if(currentUser == null){
            channel.writeAndFlush("请先登录\n");
            return;
        }

        SqlSession sqlSession = null;
        try{
            //解析请求参数
            NotReadMessagesRequest notReadMessagesRequest = JSON.parseObject(JSON.toJSONString(request),NotReadMessagesRequest.class);
            String username = notReadMessagesRequest.getUsername();
            String targetUser = notReadMessagesRequest.getTargetUser();
            //验证参数完整性

            if(username == null || targetUser == null){
                channel.writeAndFlush("参数错误：用户名和目标用户不能为空\n");
                return;
            }

            //获取SqlSession 并手动控制事务
            sqlSession = MyBatisUtils.getSqlSession(false);

            //先查询未读消息
            List<ChatMessage> notReadMessages = chatMessageMapper.queryPrivateNotReadMessages(username,targetUser);
            int unreadCount = notReadMessages.size();

            //如果有未读消息更新为已读
            if(unreadCount > 0){
                chatMessageMapper.updateUnreadToRead(username,targetUser);
                sqlSession.commit();
            }

            //构建回应
            Map<String,Object> response = new HashMap<>();
            response.put("type","notread");
            response.put("count",unreadCount);
            response.put("notReadMessages",notReadMessages);
            response.put("status","success");
            response.put("msg","成功获取并标记"+unreadCount+"条未读数据");

            channel.writeAndFlush(JSON.toJSONString(response)+"\n");

        }catch (Exception e){
            //发生异常时回滚
            if(sqlSession != null){
                sqlSession.rollback();
            }
            e.printStackTrace();
            //构建回应
            Map<String,Object> response = new HashMap<>();
            response.put("type","notread");
            response.put("status","error");
            response.put("msg",e.getMessage());
            channel.writeAndFlush(JSON.toJSONString(response)+"\n");
        }finally {
            if(sqlSession != null){
                sqlSession.close();
            }
        }
    }

    /**
     * 处理添加好友的请求
     * @param request
     * @param channel
     */
    private void handleAddFriend(Map<String, Object> request, Channel channel) {
        if(currentUser == null){
            channel.writeAndFlush("请先登录\n");
            return;
        }
        String msg = null;
        AddFriendRequest addFriendRequest = JSON.parseObject(JSON.toJSONString(request), AddFriendRequest.class);
        Integer userId = addFriendRequest.getUserId();
        String targetUserName = addFriendRequest.getTargetUser();

        User targetUser = userMapper.check(targetUserName);
        if(targetUser == null){
            msg = "该用户不存在！！！";
        }else{
            Integer targetId = targetUser.getId();
            Friend check = friendMapper.check(userId, targetId);
            if(check != null){
                msg = "已经有该用户的好友啦，快去聊天吧！！！";
            }else{
                friendMapper.addFriend(userId,targetId);
            }
        }

        //构建用户响应
        Map<String , Object> response = new HashMap<>();
        response.put("type","add_friend");
        response.put("msg",msg);

        channel.writeAndFlush(JSON.toJSONString(response)+"\n");

    }

    /**
     * 处理拉取历史消息请求
     * @param request
     * @param channel
     */
    private void handleHistory(Map<String, Object> request, Channel channel) {
        if(currentUser == null){
            channel.writeAndFlush("请先登录\n");
            return;
        }
        List<ChatMessage> historyMessages;
        HistoryMsgRequest historyMsgRequest = JSON.parseObject(JSON.toJSONString(request), HistoryMsgRequest.class);
        String targetUser = historyMsgRequest.getTargetUser();
        String username = historyMsgRequest.getUsername();
        Integer limit = historyMsgRequest.getLimit();
        if(targetUser != null){
            //拉取与指定用户的私聊历史消息
            historyMessages = chatMessageMapper.queryPrivateHistoryMessages(username,targetUser,limit);
        }else{
            //拉取所有相关历史
            historyMessages = chatMessageMapper.queryHistoryMessages(username,limit);
        }

        //构建历史消息响应
        Map<String ,Object> response = new HashMap<>();
        response.put("type","history");
        response.put("count",historyMessages.size());
        response.put("messages",historyMessages);

        //System.out.println(com.alibaba.fastjson2.JSON.toJSONString(response));

        //发送历史消息给客户端
        channel.writeAndFlush(com.alibaba.fastjson2.JSON.toJSONString(response)+"\n");
    }

    /**
     * 处理注册请求
     * @param requst 请求
     * @param channel 客户端通道
     */
    private void handleRegister(Map<String,Object> requst,Channel channel) {
        boolean isRegisterSuccess = false;
        AuthRequest authReq = JSON.parseObject(JSON.toJSONString(requst), AuthRequest.class);
        String msg = null;

        if(authReq.getUsername() == null || authReq.getPassword() == null){
            msg = "注册失败，账号或者密码不能为空！！！";
        }else{
            //校验账户是否存在
            User existUser = userMapper.check(authReq.getUsername());
            if(existUser != null){
                msg="注册失败，用户名已经存在，换一个试试吧！！！";
            }else{
                //注册新用户
                isRegisterSuccess = true;
                User user = new User(authReq.getUsername(), authReq.getPassword(), authReq.getNickname());
                userMapper.register(user);
            }
        }


        //构建返回消息
        HashMap<String,Object> resp = new HashMap<>();
        resp.put("type","register");
        resp.put("msg",msg);
        channel.writeAndFlush(JSON.toJSONString(resp)+"\n");


        //channel.writeAndFlush("注册成功，请登录");
    }

    /**
     * 处理登录请求
     * @param request 请求
     * @param channel 客户端通道
     */
    private void handleLogin(Map<String ,Object> request,Channel channel){
        boolean isLoginSuccess  = false;
        AuthRequest authReq = JSON.parseObject(JSON.toJSONString(request), AuthRequest.class);
        String msg = null;
        User user = null;
        if(authReq.getUsername() == null || authReq.getPassword() == null){
            msg = "登录失败，账号或密码不能为空！！！";
        }else{
            //检测帐号密码
            user = userMapper.check(authReq.getUsername());
            if(user == null){
                msg = "登陆失败，用户名不存在！！！";
            }else{
                user = userMapper.login(authReq.getUsername(),authReq.getPassword());
                if(user == null){
                    msg = "登陆失败，密码错误！！！";
                }else{
                    isLoginSuccess = true;
                    //绑定用户与channel
                    currentUser = user;
                    USER_CHANNEL_MAP.put(user.getId(),channel);
                    ALL_CHANNELS.add(channel);
                }
            }
        }

        if(isLoginSuccess){
            //返回用户信息
            Map<String,Object> resp = new HashMap<>();
            resp.put("type","login_success");
            resp.put("user",user);
            channel.writeAndFlush(JSON.toJSONString(resp)+"\n");
        }else{
            //返回用户信息
            Map<String,Object> resp = new HashMap<>();
            resp.put("type","login_failed");
            resp.put("reason",msg);
            channel.writeAndFlush(JSON.toJSONString(resp)+"\n");
        }

        //自动拉取好友列表
        //handleFriendList(null,channel);
    }


    /**
     * 处理获取好友列表请求
     * @param requst
     * @param channel
     */
    private void handleFriendList(Map<String,Object> requst, Channel channel) {
        if(currentUser == null){
            channel.writeAndFlush("请先登录\n");
            return;
        }

        //查询好友列表
        List<Friend> friends = friendMapper.findFriendsByUserId(currentUser.getId());


        //构建响应
        Map<String,Object> resp = new HashMap<>();
        resp.put("type","friends");
        resp.put("friends",friends);
        channel.writeAndFlush(JSON.toJSONString(resp)+"\n");
    }

    /**
     * 处理聊天请求
     * @param request
     * @param channel
     */
    private void handleChat(Map<String,Object> request,Channel channel){
        ChatRequest chatReq = JSON.parseObject(JSON.toJSONString(request), ChatRequest.class);
        ChatMessage chatMessage = chatReq.getChatMessage();
        String targetUsername = chatMessage.getReceiver();
        User target = userMapper.check(targetUsername);
        Integer targetId = target.getId();
        Channel targetChannel = USER_CHANNEL_MAP.get(targetId);
        if(targetChannel != null){
            chatMessage.setRead(true);
            targetChannel.writeAndFlush(buildDisplayMsg(chatMessage,currentUser.getUsername()+"发来"));
        }else{
            channel.writeAndFlush(buildSystemMsg("对方不在线，消息已储存到数据库！！！"));
        }
        chatMessageMapper.insertMessage(chatMessage);
    }

    /**
     * 构建用户可见的消息格式
     * @param chatMsg 聊天消息实体
     * @param prefix 前缀
     * @return 消息的json字符串
     */
    private String buildDisplayMsg(ChatMessage chatMsg,String prefix){
        Map<String,Object> msg = new HashMap<>();
        msg.put("type","chat");
        msg.put("prefix",prefix);
        msg.put("content",chatMsg.getContent());
        msg.put("time",sdf.format(chatMsg.getSendTime()));
        return JSON.toJSONString(msg)+"\n";
    }

    /**
     * 构建系统消息
     * @param content 系统消息内容
     * @return 系统消息的json字符串，包含消息内容和时间
     */
    private String buildSystemMsg(String content){
        Map<String ,Object> msg = new HashMap<>();
        msg.put("type","system");
        msg.put("content",content);
        msg.put("time",sdf.format(new Date()));
        return com.alibaba.fastjson2.JSON.toJSONString(msg)+"\n";
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        if(currentUser != null){
            USER_CHANNEL_MAP.remove(currentUser.getId());
        }
        ALL_CHANNELS.remove(ctx.channel());
    }
}
